use std::{
    any::Any,
    cell::UnsafeCell,
    collections::HashMap,
    sync::{
        atomic::{AtomicU64, Ordering},
        Arc, LazyLock, Mutex,
    },
};

use crate::inode::DfsInode;

bitflags::bitflags! {
    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
    pub(crate) struct DfsMode: u32 {
        const READ = 0x1;
        const WRITE = 0x2;
        const SEEK = 0x4;
        const FCNTL = 0x8;
        const NOBLOCK = 0x10;
    }
}

pub(crate) struct DfsFile {
    pub(crate) inode: Arc<DfsInode>,
    // private 只会对应一个打开的文件, 不会被共享, 访问它是安全的
    pub(crate) private: UnsafeCell<Box<dyn Any + Send>>,
    pub(crate) mode: DfsMode,
    pub(crate) pos: u64,
}

unsafe impl Send for DfsFile {}
unsafe impl Sync for DfsFile {}

impl DfsFile {
    pub(crate) fn new(data: Box<dyn Any + Send>, inode: Arc<DfsInode>, mode: DfsMode) -> Self {
        Self { inode, private: UnsafeCell::new(data), mode, pos: 0 }
    }
}

static FILE_NUM: AtomicU64 = AtomicU64::new(0);
static FILE_TABLE: LazyLock<Mutex<HashMap<u64, Arc<Mutex<DfsFile>>>>> =
    LazyLock::new(|| Mutex::new(HashMap::new()));

fn get_unused_fd() -> u64 {
    FILE_NUM.fetch_add(1, Ordering::Relaxed)
}

pub(crate) fn push_file(file: DfsFile) -> u64 {
    let fd = get_unused_fd();
    let mut hashtable = FILE_TABLE.lock().unwrap();
    hashtable.insert(fd, Arc::new(Mutex::new(file)));
    fd
}

pub(crate) fn pop_file(fd: u64) {
    let mut hashtable = FILE_TABLE.lock().unwrap();
    hashtable.remove(&fd).unwrap();
}

pub(crate) fn get_file(fd: u64) -> Arc<Mutex<DfsFile>> {
    let hashtable = FILE_TABLE.lock().unwrap();
    let file = hashtable.get(&fd).unwrap();
    file.clone()
}
